//
// Created by liuhuan on 2022/5/14.
//

#include "register/Register.h"
#include <android/log.h>

#define  REG_LOGE(...)   __android_log_print(ANDROID_LOG_ERROR,"Register",__VA_ARGS__);
#define  REG_LOGD(...)   __android_log_print(ANDROID_LOG_DEBUG,"Register",__VA_ARGS__);

int Register::find_class(JNIEnv *env, const char *name, jclass *clazz_out) {
    jclass clazz = env->FindClass(name);
    if (clazz == nullptr) {
        REG_LOGE("Can't find %s", name);
        return -1;
    }
    *clazz_out = (jclass) env->NewGlobalRef(clazz); // 这里必须新建一个全局的引用
    return 0;
}

int Register::get_field(JNIEnv *env, jclass *clazz, const char *name, const char *sig,
                        jfieldID *field_out) {
    jfieldID filed = env->GetFieldID(*clazz, name, sig);
    if (filed == nullptr) {
        REG_LOGE("Can't find. filed name: %s, sig: %s", name, sig);
        return -1;
    }
    *field_out = filed;
    return 0;
}

void Register::register_classes(JNIEnv *env) {
    registerBoundingBox(env);
    registerDetectParams(env);
    registerDeviceInfo(env);
    registerList(env);
    registerPidInfo(env);
    registerSkyNodeGndAlgParams(env);
    registerSkyNodeGndBaseInfo(env);
    registerSkyNodeGndDetectInfoS(env);
    registerSkyNodeGndDevice(env);
    registerSkyNodeGndPTZPid(env);
    registerSkyNodeGndTrackInfo(env);
    registerTrackParams(env);
}

void Register::registerList(JNIEnv *env) {
    int ret = find_class(env, "java/util/ArrayList", &listBlock.clazz);
    if (ret != 0) {
        REG_LOGE("ArrayList_block failed");
        return;
    }
    jclass clazz = listBlock.clazz;
    // 构造方法
    listBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    listBlock.add = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");
}

void Register::registerBoundingBox(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/BoundingBox", &boxBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerBoundingBox failed");
        return;
    }
    jclass clazz = boxBlock.clazz;
    // 构造方法
    boxBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "xmin", "S", &boxBlock.xmin);
    get_field(env, &clazz, "ymin", "S", &boxBlock.ymin);
    get_field(env, &clazz, "xmax", "S", &boxBlock.xmax);
    get_field(env, &clazz, "ymax", "S", &boxBlock.ymax);
    get_field(env, &clazz, "score", "C", &boxBlock.score);
    get_field(env, &clazz, "classId", "C", &boxBlock.classId);
}

void Register::registerDetectParams(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/DetectParams", &detectParamsBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerDetectParams failed");
        return;
    }
    jclass clazz = detectParamsBlock.clazz;
    // 构造方法
    detectParamsBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "detectObjThres", "S", &detectParamsBlock.detectObjThres);
    get_field(env, &clazz, "detectMinBBoxSize", "I", &detectParamsBlock.detectMinBBoxSize);
}

void Register::registerDeviceInfo(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/DeviceInfo", &deviceInfoBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerDeviceInfo failed");
        return;
    }
    jclass clazz = deviceInfoBlock.clazz;
    // 构造方法
    deviceInfoBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "no", "C", &deviceInfoBlock.no);
    get_field(env, &clazz, "camType", "C", &deviceInfoBlock.camType);
    get_field(env, &clazz, "port", "S", &deviceInfoBlock.port);
    get_field(env, &clazz, "devStatus", "C", &deviceInfoBlock.devStatus);
}

void Register::registerPidInfo(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/PidInfo", &pidInfoBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerPidInfo failed");
        return;
    }
    jclass clazz = pidInfoBlock.clazz;
    // 构造方法
    pidInfoBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "p", "S", &pidInfoBlock.p);
    get_field(env, &clazz, "i", "S", &pidInfoBlock.i);
    get_field(env, &clazz, "d", "S", &pidInfoBlock.d);
}

void Register::registerSkyNodeGndAlgParams(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/SkyNodeGndAlgParams",
                         &algParamsBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerSkyNodeGndAlgParams failed");
        return;
    }
    jclass clazz = algParamsBlock.clazz;
    // 构造方法
    algParamsBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "devNo", "C", &algParamsBlock.devNo);
    get_field(env, &clazz, "detectParams", "Lcom/rykj/socket_lib/entity/DetectParams;",
              &algParamsBlock.detectParams);
    get_field(env, &clazz, "trackParam", "Lcom/rykj/socket_lib/entity/TrackParams;",
              &algParamsBlock.trackParam);
}

void Register::registerSkyNodeGndBaseInfo(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/SkyNodeGndBaseInfo",
                         &baseInfoBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerSkyNodeGndBaseInfo failed");
        return;
    }
    jclass clazz = baseInfoBlock.clazz;
    // 构造方法
    baseInfoBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "currentMode", "C", &baseInfoBlock.currentMode);
    get_field(env, &clazz, "ptzStatus", "C", &baseInfoBlock.ptzStatus);
    get_field(env, &clazz, "yaw", "S", &baseInfoBlock.yaw);
    get_field(env, &clazz, "pitch", "S", &baseInfoBlock.pitch);
    get_field(env, &clazz, "roll", "S", &baseInfoBlock.roll);
    get_field(env, &clazz, "rangeValid", "C", &baseInfoBlock.rangeValid);
    get_field(env, &clazz, "rangVal", "C", &baseInfoBlock.rangVal);
    get_field(env, &clazz, "mainZoom", "C", &baseInfoBlock.mainZoom);
}

void Register::registerSkyNodeGndDetectInfoS(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/SkyNodeGndDetectInfoS",
                         &detectInfoSBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerSkyNodeGndDetectInfoS failed");
        return;
    }
    jclass clazz = detectInfoSBlock.clazz;
    // 构造方法
    detectInfoSBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "devNo", "C", &detectInfoSBlock.devNo);
    get_field(env, &clazz, "camLensType", "C", &detectInfoSBlock.camLensType);
    get_field(env, &clazz, "zoom", "S", &detectInfoSBlock.zoom);
    get_field(env, &clazz, "boxLen", "C", &detectInfoSBlock.boxLen);
    get_field(env, &clazz, "boxes", "Ljava/util/List;", &detectInfoSBlock.boxes);
}

void Register::registerSkyNodeGndDevice(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/SkyNodeGndDevice", &deviceBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerSkyNodeGndDevice failed");
        return;
    }
    jclass clazz = deviceBlock.clazz;
    // 构造方法
    deviceBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "isRanging", "C", &deviceBlock.isRanging);
    get_field(env, &clazz, "devNums", "C", &deviceBlock.devNums);
    get_field(env, &clazz, "deviceInfos", "Ljava/util/List;", &deviceBlock.deviceInfos);
}

void Register::registerSkyNodeGndPTZPid(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/SkyNodeGndPTZPid", &ptzPidBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerSkyNodeGndPTZPid failed");
        return;
    }
    jclass clazz = ptzPidBlock.clazz;
    // 构造方法
    ptzPidBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "pitchP", "S", &ptzPidBlock.pitchP);
    get_field(env, &clazz, "pitchI", "S", &ptzPidBlock.pitchI);
    get_field(env, &clazz, "pitchD", "S", &ptzPidBlock.pitchD);
    get_field(env, &clazz, "yawP", "S", &ptzPidBlock.yawP);
    get_field(env, &clazz, "yawI", "S", &ptzPidBlock.yawI);
    get_field(env, &clazz, "yawD", "S", &ptzPidBlock.yawD);
}

void Register::registerSkyNodeGndTrackInfo(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/SkyNodeGndTrackInfo",
                         &trackInfoBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerSkyNodeGndTrackInfo failed");
        return;
    }
    jclass clazz = trackInfoBlock.clazz;
    // 构造方法
    trackInfoBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "devNo", "C", &trackInfoBlock.devNo);
    get_field(env, &clazz, "camLensType", "C", &trackInfoBlock.camLensType);
    get_field(env, &clazz, "zoom", "S", &trackInfoBlock.zoom);
    get_field(env, &clazz, "destIsLost", "C", &trackInfoBlock.destIsLost);
    get_field(env, &clazz, "box", "Lcom/rykj/socket_lib/entity/BoundingBox;",
              &trackInfoBlock.box);
    get_field(env, &clazz, "dstAndCenterAngleX", "S", &trackInfoBlock.dstAndCenterAngleX);
    get_field(env, &clazz, "dstAndCenterAngleY", "S", &trackInfoBlock.dstAndCenterAngleY);
    get_field(env, &clazz, "yaw", "S", &trackInfoBlock.yaw);
    get_field(env, &clazz, "pitch", "S", &trackInfoBlock.pitch);
    get_field(env, &clazz, "roll", "S", &trackInfoBlock.roll);
}

void Register::registerTrackParams(JNIEnv *env) {
    int ret = find_class(env, "com/rykj/socket_lib/entity/TrackParams", &trackParamsBlock.clazz);
    if (ret != 0) {
        REG_LOGE("registerTrackParams failed");
        return;
    }
    jclass clazz = trackParamsBlock.clazz;
    // 构造方法
    trackParamsBlock.constructor = env->GetMethodID(clazz, "<init>", "()V");
    // 成员
    get_field(env, &clazz, "searchSize", "I", &trackParamsBlock.searchSize);
    get_field(env, &clazz, "tmplSize", "I", &trackParamsBlock.tmplSize);
    get_field(env, &clazz, "srcWidth", "I", &trackParamsBlock.srcWidth);
    get_field(env, &clazz, "srcHeight", "I", &trackParamsBlock.srcHeight);
    get_field(env, &clazz, "thresholdLow", "S", &trackParamsBlock.thresholdLow);
    get_field(env, &clazz, "thresholdHigh", "S", &trackParamsBlock.thresholdHigh);
    get_field(env, &clazz, "longtermSearchSize", "I", &trackParamsBlock.longtermSearchSize);
}

const BoundingBox_block &Register::getBoxBlock() const {
    return boxBlock;
}
